package com.hex.ds.hdtp.core.inf.metadata.service.impl;

import cn.hutool.core.util.StrUtil;
import com.hex.ds.hdtp.core.inf.metadata.repository.ISourceConfInfoRepository;
import lombok.extern.slf4j.Slf4j;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @Package com.hex.ds.hdtp.core.inf.metadata.service.impl
 * @ClassName AbstractHiveQLMethodService
 * @Description HIVEQL类型数据库（如Hive、Impala）元数据管理抽象类
 * @Author gj.xu
 * @Date 2024/2/5 12:43
 * @Version v2.0
 **/
@Slf4j
public abstract class AbstractHiveQLMethodService extends AbstractSourceMethodService {

    public AbstractHiveQLMethodService(ISourceConfInfoRepository sourceConfInfoRepository) {
        super(sourceConfInfoRepository);
    }

    /**
     * @Method extractTableFields <br>
     * @Param resultSet SQL查询的ResultSet对象
     * @Param tableFieldsMap 要用列名和值填充的映射
     * @Param fieldType 查询出数据中为字段类型的列名
     * @Return 如果该行应添加到resultList，则为True，否则为false <br>
     * @Description 判断是否从SQL结果中提取该行字段数据<br>
     * @Author Yin.Yang<br>
     * @Date 2023/9/6 17:11 <br>
     * @Version V1.0<br>
     */
    protected boolean extractTableFields(ResultSet resultSet, Map<String, String> tableFieldsMap, List<String> partitionColumns, String fieldType) throws SQLException {
        ResultSetMetaData metaData = resultSet.getMetaData();
        for (int i = 1; i <= metaData.getColumnCount(); i++) {
            String columnName = metaData.getColumnName(i);
            String value = resultSet.getString(i);
            // 设置分区字段值
            if (partitionColumns != null && partitionColumns.contains(columnName)) {
                tableFieldsMap.put("partitioningColumn", "Y");
            } else {
                tableFieldsMap.put("partitioningColumn", "N");
            }
            // 对字段类型列进行特殊处理
            if (fieldType.equalsIgnoreCase(columnName)) {
                if (value == null) return false;
                populateColumnTypeAndLength(value, tableFieldsMap);
            } else {
                tableFieldsMap.put(columnName, value);
            }
        }
        return true;
    }

    /**
     * @Method populateColumnTypeAndLength <br>
     * @Param value data_type列的值
     * @Param tableFieldsMap 要填充的映射
     * @Return void <br>
     * @Description 拆分data_type获取字段类型和字段长度<br>
     * @Author Yin.Yang<br>
     * @Date 2023/9/6 17:14 <br>
     * @Version V1.0<br>
     */
    private void populateColumnTypeAndLength(String value, Map<String, String> tableFieldsMap) {
        if (value.contains("(")) {
            String[] splitValue = value.split("\\(", 2);
            tableFieldsMap.put("columnTypeLength", value);
            tableFieldsMap.put("columnType", splitValue[0]);
            tableFieldsMap.put("columnLength", splitValue[1].replace(")", ""));
        } else {
            tableFieldsMap.put("columnType", value);
            tableFieldsMap.put("columnLength", "");
        }
    }


    @Override
    protected String queryProceduresContentSql(String schemaName, String proceduresName) {
        throw new RuntimeException("HiveQL（Hive、Impala） 不支持获取存储过程");
    }

    @Override
    protected String getProcedureContentFromResultSet(ResultSet resultSet) throws SQLException {
        throw new RuntimeException("HiveQL（Hive、Impala） 不支持获取存储过程");
    }

    @Override
    public String queryTableStructureSql(String schema, String table) {
        String querySql = "DESCRIBE {}.{} ";
        return StrUtil.format(querySql, schema, table);
    }


    /**
     * @Method getTableAllFieldSqlLimitSql
     * @Param fields
     * @Param schema
     * @Param table
     * @Param whereSql
     * @Param extractScope
     * @Param offset
     * @Param sortField
     * @Return java.lang.String
     * @Description 获取分批比对全字段明细对比的SQL
     * @Author gj.xu
     * @Date 2024/2/1 20:53
     * @Version V2.0
     */
    @Override
    public String getTableAllFieldSqlLimitSql(String fields, String schema, String table, String whereSql, Long extractScope, Long offset, String sortField) {
        String querySql = "SELECT {}\n" +
                "FROM (\n" +
                "  SELECT {}, ROW_NUMBER() OVER (ORDER BY {}) AS row_num\n" +
                "  FROM {}.{} {}\n" +
                ") AS PagedResults\n" +
                "WHERE row_num > {}\n" +
                "ORDER BY {} LIMIT {}";
        return StrUtil.format(querySql, fields, fields, sortField, schema, table, whereSql, offset, sortField, extractScope);
    }


    /**
     * @Method getTablePartitionFieldSql
     * @Param schema
     * @Param table
     * @Return java.lang.String
     * @Description 获取分区字段的SQL
     * @Author gj.xu
     * @Date 2024/2/1 20:20
     * @Version V2.0
     */
    @Override
    public String getTablePartitionFieldSql(String schema, String table) {
        String querySql = "SHOW PARTITIONS {}.{} ";
        return StrUtil.format(querySql, schema, table);
    }


    /**
     * @Method getCreateTableBodySql
     * @Param columnName
     * @Param columnType
     * @Param columnExt
     * @Return java.lang.String
     * @Description 获取创建表时Body部分SQL
     * @Author gj.xu
     * @Date 2024/2/1 17:36
     * @Version V2.0
     */
    public String getCreateTableBodySql(String columnName, String columnType, String columnExt, String columnComment) {
        String querySql = "`{}` {}{} {},\n";
        return StrUtil.format(querySql, columnName, columnType, columnExt, columnComment);
    }


    /**
     * @Method getCreateTablePartitionSql
     * @Param partitionFieldName
     * @Return java.lang.String
     * @Description 获取创建表时分区部分SQL
     * @Author gj.xu
     * @Date 2024/2/1 19:31
     * @Version V2.0
     */
    public String getCreateTablePartitionSql(String partitionFieldName) {
        String querySql = "PARTITIONED BY ( {} )";
        return StrUtil.format(querySql, partitionFieldName);
    }


    /**
     * @Method getCreateTablePartitionBodySql
     * @Param partitionFieldName
     * @Param columnType
     * @Return java.lang.String
     * @Description 获取创建表时分区Body部分SQL
     * @Author gj.xu
     * @Date 2024/2/1 19:28
     * @Version V2.0
     */
    public String getCreateTablePartitionBodySql(String partitionFieldName, String columnType) {
        String querySql = " `{}` {},";
        return StrUtil.format(querySql, partitionFieldName, columnType);
    }

    /**
     * @Method getCreateTableCommentSql
     * @Param columnComment
     * @Return java.lang.String
     * @Description 获取创建表时Comment部分SQL
     * @Author gj.xu
     * @Date 2024/2/1 19:22
     * @Version V2.0
     */
    public String getCreateTableCommentSql(String columnComment) {
        String querySql = "COMMENT '{}'";
        return StrUtil.format(querySql, columnComment);
    }

    /**
     * @Method getStrDataType
     * @Param
     * @Return java.util.List<java.lang.String>
     * @Description 获取字符数据类型
     * @Author gj.xu
     * @Date 2024/2/21 14:20
     * @Version V2.0
     */
    @Override
    public List<String> getStrDataType() {
        return Arrays.asList("CHAR", "VARCHAR", "STRING");
    }

    /**
     * @Method getNumDataType
     * @Param
     * @Return java.util.List<java.lang.String>
     * @Description 获取数值数据类型
     * @Author gj.xu
     * @Date 2024/2/21 15:10
     * @Version V2.0
     */
    @Override
    public List<String> getNumDataType() {
        return Arrays.asList("TINYINT", "SMALLINT", "INT", "INTEGER", "BIGINT", "FLOAT", "DOUBLE", "DECIMAL");
    }

    /**
     * @Method getAccuracyDataType
     * @Param
     * @Return java.util.List<java.lang.String>
     * @Description 获取精度数据类型
     * @Author gj.xu
     * @Date 2024/2/21 15:32
     * @Version V2.0
     */
    @Override
    public List<String> getAccuracyDataType() {
        return Arrays.asList("FLOAT", "DOUBLE", "DECIMAL");
    }
}
